"""Tag Service - 标签管理和匹配服务（混合版：规则80% + AI 20%）."""

from __future__ import annotations

import json
import os
import re
from typing import Optional, Any

from sqlalchemy.orm import Session

from ..models.tag import Tag
from ..models.lead_tag import LeadTag
from ..repositories.tag_repository import TagRepository
from ..repositories.lead_tag_repository import LeadTagRepository
from ..schemas.tag import TagCreate, TagUpdate


class TagMatchResult:
    """标签匹配结果."""

    def __init__(self, tag_id: int, tag_name: str, confidence: float, level: int):
        self.tag_id = tag_id
        self.tag_name = tag_name
        self.confidence = confidence
        self.level = level


class TagService:
    """标签服务 - 混合版（规则80% + AI 20%）.

    核心功能：
    1. Tag CRUD管理
    2. 从文本中匹配预定义标签（混合引擎：规则 + AI语义理解）
    3. Lead标签关联管理

    AI增强场景（20%边缘情况）：
    - 语义理解："出门就是轨道交通" → "近地铁"
    - 隐含需求："孩子明年上小学" → "学区房"
    - 同义词识别："宁静"/"清幽" → "安静"
    - 否定理解："不要太高的楼层" → 排除"高楼层"
    - 协同推理："老人住，楼层不能太高" → "低楼层" + "电梯房"
    """

    def __init__(
        self,
        tag_repo: TagRepository,
        lead_tag_repo: LeadTagRepository,
        qwen_api_key: Optional[str] = None,
        hunyuan_secret_id: Optional[str] = None,
        hunyuan_secret_key: Optional[str] = None,
    ):
        self.tag_repo = tag_repo
        self.lead_tag_repo = lead_tag_repo

        # AI API配置（可选，用于20%边缘场景）
        self.qwen_api_key = qwen_api_key or os.getenv("QWEN_API_KEY")
        self.hunyuan_secret_id = hunyuan_secret_id or os.getenv("HUNYUAN_SECRET_ID")
        self.hunyuan_secret_key = hunyuan_secret_key or os.getenv("HUNYUAN_SECRET_KEY")

    # ========== Tag管理（CRUD） ==========

    def create_tag(self, tag_data: TagCreate) -> Tag:
        """创建新标签."""
        return self.tag_repo.create(tag_data)

    def get_tag(self, tag_id: int) -> Tag | None:
        """获取标签详情."""
        return self.tag_repo.get(tag_id)

    def get_tag_by_name(self, name: str) -> Tag | None:
        """根据名称获取标签."""
        return self.tag_repo.get_by_name(name)

    def update_tag(self, tag_id: int, tag_data: TagUpdate) -> Tag | None:
        """更新标签."""
        tag = self.tag_repo.get(tag_id)
        if not tag:
            return None
        return self.tag_repo.update(tag, tag_data)

    def delete_tag(self, tag_id: int) -> bool:
        """删除标签（软删除：设置is_active=False）."""
        tag = self.tag_repo.get(tag_id)
        if tag:
            tag.is_active = False
            self.tag_repo.session.flush()
            return True
        return False

    def list_tags(
        self, category: str | None = None, level: int | None = None, skip: int = 0, limit: int = 100
    ) -> list[Tag]:
        """列出标签."""
        if category:
            return self.tag_repo.get_by_category(category, skip, limit)
        elif level:
            return self.tag_repo.get_by_level(level, skip, limit)
        else:
            return self.tag_repo.get_all_active(skip, limit)

    def get_popular_tags(self, limit: int = 20) -> list[Tag]:
        """获取热门标签."""
        return self.tag_repo.get_popular_tags(limit)

    def get_statistics(self) -> dict[str, Any]:
        """获取标签统计."""
        return self.tag_repo.get_statistics()

    # ========== 标签匹配引擎（简化版 - 规则匹配） ==========

    def match_tags_from_text(self, text: str, max_tags: int = 4) -> list[dict[str, Any]]:
        """从文本中匹配预定义标签（混合引擎：规则80% + AI 20%）.

        算法：
        1. 阶段1: 规则引擎关键词匹配（快速，零成本）
        2. 阶段2: 如果规则匹配<3个标签 且 文本>20字 → 调用AI语义理解
        3. 合并结果，按level和confidence排序
        4. 返回前max_tags个

        Args:
            text: 要匹配的文本（备注）
            max_tags: 最多返回标签数（默认4）

        Returns:
            [
                {"tag_id": 1, "tag_name": "近地铁", "confidence": 0.95, "level": 3, "source": "ai"},
                {"tag_id": 5, "tag_name": "安静", "confidence": 0.9, "level": 2, "source": "rule"}
            ]
        """
        if not text or len(text.strip()) < 2:
            return []

        # 阶段1: 规则引擎匹配
        rule_matched = self._rule_match_tags(text)

        # 阶段2: 决策是否调用AI
        if self._should_use_ai(text, rule_matched):
            # 调用AI语义理解
            ai_matched = self._ai_match_tags(text)
            # 合并结果（去重，保留高置信度）
            merged = self._merge_tag_results(rule_matched, ai_matched)
            # 按level和confidence排序
            final = self._sort_by_priority(merged)
        else:
            # 只用规则引擎结果
            final = self._sort_by_priority(rule_matched)

        return final[:max_tags]

    def _rule_match_tags(self, text: str) -> list[dict[str, Any]]:
        """规则引擎：关键词匹配（覆盖80%场景）."""
        # 获取所有active标签（已按level降序排序）
        all_tags = self.tag_repo.get_all_active(limit=200)

        matched = []
        text_lower = text.lower()

        for tag in all_tags:
            if self._is_tag_matched(text_lower, tag):
                matched.append(
                    {
                        "tag_id": tag.id,
                        "tag_name": tag.name,
                        "confidence": 0.90,  # 规则匹配固定置信度
                        "level": tag.level,
                        "source": "rule",
                    }
                )

        return matched

    def _is_tag_matched(self, text_lower: str, tag: Tag) -> bool:
        """检查标签是否匹配文本（简单关键词匹配）.

        匹配规则：
        1. 如果tag.keywords存在，检查任一关键词是否在text中
        2. 如果tag.keywords为空，检查tag.name是否在text中
        """
        # 优先使用keywords
        if tag.keywords:
            keywords = [kw.strip().lower() for kw in tag.keywords.split(",")]
            return any(kw in text_lower for kw in keywords if kw)

        # 如果没有keywords，使用tag name
        return tag.name.lower() in text_lower

    def _should_use_ai(self, text: str, rule_matched: list[dict[str, Any]]) -> bool:
        """决策是否需要调用AI（20%边缘场景）.

        策略：
        - 规则已匹配>=3个标签 → 不调用AI（80%场景）
        - 文本<20字 → 不调用AI（太短，语义不足）
        - 无可用AI → 不调用AI
        - 其他 → 调用AI（20%场景）
        """
        # 检查是否有可用AI
        has_ai = self.qwen_api_key or (self.hunyuan_secret_id and self.hunyuan_secret_key)
        if not has_ai:
            return False

        # 规则已足够
        if len(rule_matched) >= 3:
            return False

        # 文本太短
        if len(text) < 20:
            return False

        return True

    def _ai_match_tags(self, text: str) -> list[dict[str, Any]]:
        """AI语义理解：从预定义标签库中选择最匹配的标签（20%边缘场景）.

        核心价值：
        1. 语义理解："出门就是轨道交通" → "近地铁"
        2. 隐含需求："孩子明年上小学" → "学区房"
        3. 同义词识别："宁静" → "安静"
        4. 否定理解："不要太高" → 排除"高楼层"
        5. 协同推理："老人住" → "低楼层" + "电梯房" + "安静"
        """
        # 获取所有可选标签
        all_tags = self.tag_repo.get_all_active(limit=200)

        # 尝试Qwen3
        if self.qwen_api_key:
            try:
                result = self._call_qwen_api(text, all_tags)
                if result:
                    return result
            except Exception as e:
                print(f"Qwen3 AI调用失败: {str(e)}")

        # 尝试腾讯混元
        if self.hunyuan_secret_id and self.hunyuan_secret_key:
            try:
                result = self._call_hunyuan_api(text, all_tags)
                if result:
                    return result
            except Exception as e:
                print(f"腾讯混元AI调用失败: {str(e)}")

        # AI都失败，返回空
        return []

    def _build_ai_prompt(self, text: str, available_tags: list[Tag]) -> str:
        """构建AI提示词：让AI从预定义标签库中选择."""
        # 构建标签库列表
        tag_list = []
        for tag in available_tags:
            tag_info = f"- {tag.name} (优先级:{tag.level}星"
            if tag.keywords:
                tag_info += f", 关键词:{tag.keywords}"
            if tag.description:
                tag_info += f", 说明:{tag.description}"
            tag_info += ")"
            tag_list.append(tag_info)

        tags_str = "\n".join(tag_list[:50])  # 限制50个标签避免prompt过长

        return f"""你是房产CRM的需求分析专家。请从预定义标签库中选择最匹配的标签（注意：只能从下面的标签库中选择，不要创造新标签）。

【客户备注】
{text}

【可选标签库】
{tags_str}

【要求】
1. 理解真实需求（不只是关键词匹配）：
   - "出门就是轨道交通" → "近地铁"
   - "孩子明年上小学" → "学区房"
   - "宁静"/"清幽" → "安静"
2. 理解否定需求：
   - "不要太高的楼层" → 排除"高楼层"
3. 协同推理：
   - "老人住，楼层不能太高" → "低楼层" + "电梯房" + "安静"
4. 优先选择高星级标签（3星>2星>1星）
5. 最多选择3-4个标签
6. 给出置信度评分(0-1)

【输出格式】
只输出JSON（不要markdown代码块）：
{{
  "tags": [
    {{"name": "标签名", "confidence": 0.95}},
    {{"name": "标签名", "confidence": 0.88}}
  ]
}}

注意：标签name必须严格从上面的标签库中选择，不能自己创造！"""

    def _call_qwen_api(self, text: str, available_tags: list[Tag]) -> list[dict[str, Any]]:
        """调用Qwen3 API进行语义匹配."""
        try:
            import dashscope
            from http import HTTPStatus

            dashscope.api_key = self.qwen_api_key

            response = dashscope.Generation.call(
                model="qwen-turbo",
                messages=[{"role": "user", "content": self._build_ai_prompt(text, available_tags)}],
                result_format="message",
                temperature=0.3,
                top_p=0.8,
                max_tokens=500,
            )

            if hasattr(response, "status_code") and response.status_code == HTTPStatus.OK:
                ai_text = response.output.choices[0]["message"]["content"]
                return self._parse_ai_response(ai_text)
            else:
                return []

        except ImportError:
            print("dashscope未安装: pip install dashscope")
            return []
        except Exception as e:
            print(f"Qwen3调用异常: {str(e)}")
            return []

    def _call_hunyuan_api(self, text: str, available_tags: list[Tag]) -> list[dict[str, Any]]:
        """调用腾讯混元API进行语义匹配."""
        try:
            import hashlib
            import hmac
            import time
            from datetime import datetime
            import requests

            service = "hunyuan"
            host = "hunyuan.tencentcloudapi.com"
            endpoint = f"https://{host}"
            region = "ap-beijing"
            action = "ChatCompletions"
            version = "2023-09-01"
            algorithm = "TC3-HMAC-SHA256"

            timestamp = int(time.time())
            date = datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d")

            payload = {
                "Model": "hunyuan-lite",
                "Messages": [
                    {"Role": "user", "Content": self._build_ai_prompt(text, available_tags)}
                ],
                "Temperature": 0.3,
                "TopP": 0.8,
            }
            payload_str = json.dumps(payload)

            # 构建签名
            http_request_method = "POST"
            canonical_uri = "/"
            canonical_querystring = ""
            ct = "application/json"
            canonical_headers = f"content-type:{ct}\nhost:{host}\n"
            signed_headers = "content-type;host"
            hashed_request_payload = hashlib.sha256(payload_str.encode("utf-8")).hexdigest()
            canonical_request = (
                f"{http_request_method}\n{canonical_uri}\n{canonical_querystring}\n"
                f"{canonical_headers}\n{signed_headers}\n{hashed_request_payload}"
            )

            credential_scope = f"{date}/{service}/tc3_request"
            hashed_canonical_request = hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()
            string_to_sign = (
                f"{algorithm}\n{timestamp}\n{credential_scope}\n{hashed_canonical_request}"
            )

            def _sign(key: bytes, msg: str) -> bytes:
                return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()

            secret_date = _sign(f"TC3{self.hunyuan_secret_key}".encode("utf-8"), date)
            secret_service = _sign(secret_date, service)
            secret_signing = _sign(secret_service, "tc3_request")
            signature = hmac.new(
                secret_signing, string_to_sign.encode("utf-8"), hashlib.sha256
            ).hexdigest()

            authorization = (
                f"{algorithm} Credential={self.hunyuan_secret_id}/{credential_scope}, "
                f"SignedHeaders={signed_headers}, Signature={signature}"
            )

            headers = {
                "Authorization": authorization,
                "Content-Type": ct,
                "Host": host,
                "X-TC-Action": action,
                "X-TC-Timestamp": str(timestamp),
                "X-TC-Version": version,
                "X-TC-Region": region,
            }

            response = requests.post(endpoint, headers=headers, data=payload_str, timeout=10)

            if response.status_code == 200:
                result = response.json()
                if "Response" in result and "Choices" in result["Response"]:
                    content = result["Response"]["Choices"][0]["Message"]["Content"]
                    return self._parse_ai_response(content)
            return []

        except Exception as e:
            print(f"腾讯混元调用异常: {str(e)}")
            return []

    def _parse_ai_response(self, ai_text: str) -> list[dict[str, Any]]:
        """解析AI返回的JSON并转换为标准格式."""
        try:
            # 移除markdown代码块
            ai_text = re.sub(r"```json\s*|\s*```", "", ai_text).strip()

            # 解析JSON
            data = json.loads(ai_text)
            tags_data = data.get("tags", [])

            # 验证tag name是否在预定义库中
            all_tag_names = {tag.name for tag in self.tag_repo.get_all_active(limit=200)}

            matched = []
            for tag_item in tags_data:
                tag_name = tag_item.get("name")
                if tag_name and tag_name in all_tag_names:
                    # 获取tag详情
                    tag = self.tag_repo.get_by_name(tag_name)
                    if tag:
                        matched.append(
                            {
                                "tag_id": tag.id,
                                "tag_name": tag.name,
                                "confidence": float(tag_item.get("confidence", 0.85)),
                                "level": tag.level,
                                "source": "ai",
                            }
                        )

            return matched

        except (json.JSONDecodeError, KeyError, ValueError) as e:
            print(f"AI响应解析失败: {str(e)}, 原始: {ai_text}")
            return []

    def _merge_tag_results(
        self, rule_tags: list[dict[str, Any]], ai_tags: list[dict[str, Any]]
    ) -> list[dict[str, Any]]:
        """合并规则和AI结果（去重，保留高置信度）."""
        tag_dict = {}

        # 先添加规则标签
        for tag in rule_tags:
            tag_dict[tag["tag_id"]] = tag

        # AI标签覆盖或补充
        for tag in ai_tags:
            tag_id = tag["tag_id"]
            if tag_id not in tag_dict or tag["confidence"] > tag_dict[tag_id]["confidence"]:
                tag_dict[tag_id] = tag

        return list(tag_dict.values())

    def _sort_by_priority(self, tags: list[dict[str, Any]]) -> list[dict[str, Any]]:
        """按优先级排序（level降序 → confidence降序）."""
        return sorted(tags, key=lambda x: (x["level"], x["confidence"]), reverse=True)

    # ========== Lead标签关联管理 ==========

    def attach_tags_to_lead(
        self, lead_id: int, matched_tags: list[dict[str, Any]], session: Session
    ) -> list[LeadTag]:
        """将匹配的标签关联到Lead.

        Args:
            lead_id: Lead ID
            matched_tags: match_tags_from_text的返回结果
            session: 数据库会话

        Returns:
            创建的LeadTag列表
        """
        created_tags = []

        for match in matched_tags:
            # 检查是否已存在
            existing = self.lead_tag_repo.get_by_lead_and_tag(lead_id, match["tag_id"])
            if existing:
                continue

            # 创建LeadTag
            lead_tag = LeadTag(
                lead_id=lead_id,
                tag_id=match["tag_id"],
                confidence=match["confidence"],
                source=match.get("source", "rule"),
            )
            session.add(lead_tag)
            created_tags.append(lead_tag)

            # 增加标签使用计数
            self.tag_repo.increment_usage_count(match["tag_id"])

        session.flush()
        return created_tags

    def get_lead_tags(self, lead_id: int) -> list[LeadTag]:
        """获取Lead的所有标签."""
        return self.lead_tag_repo.get_by_lead(lead_id)

    def remove_tag_from_lead(self, lead_id: int, tag_id: int) -> bool:
        """从Lead移除标签."""
        return self.lead_tag_repo.delete_by_lead_and_tag(lead_id, tag_id)

    def build_tag_names_string(self, lead_tags: list[LeadTag]) -> str:
        """构建tag_names字符串（用于Lead.tag_names字段）.

        Args:
            lead_tags: LeadTag列表

        Returns:
            "近地铁,学区房,安静"
        """
        if not lead_tags:
            return ""

        # 按confidence降序排序
        sorted_tags = sorted(lead_tags, key=lambda x: x.confidence, reverse=True)

        # 提取tag names
        tag_names = [lt.tag.name for lt in sorted_tags if lt.tag]

        return ",".join(tag_names)
